﻿using System;
using System.Threading;
using System.Collections.Generic;
using System.Text;

namespace Devsoft.Utilities
{
	public delegate void AsynThreadFunc (params object[] args);
	public delegate void AsynThreadEventHandler(object sender, ThreadEventArgs e);

	/// <summary>
	/// Thread Event Argument
	/// </summary>
	public class ThreadEventArgs : EventArgs
	{        
		private string _message;
		private bool _canceled = false;

		/// <summary>
		/// Event message
		/// </summary>
		public string Message
		{
			get { return _message; }
			set { _message = value; }
		}

		/// <summary>
		/// Operation canceled
		/// </summary>
		public bool Canceled
		{
			get { return _canceled; }
			set { _canceled = value; }
		}

		/// <summary>
		/// Create a new ThreadEventArgs instance
		/// </summary>
		/// <param name="msg"></param>
		public ThreadEventArgs(string msg)
		{
			_message = msg;
		}
	}

	/// <summary>
	/// Thread User State
	/// </summary>
	public enum ThreadUserState
	{ 
		Online,
		Offline,
		Locked,
		Active,
		New,
	}

	/// <summary>
	/// Asynchronous Thread
	/// </summary>
	public class AsyncThread
	{

		// =================================================
		// Events
		// =================================================

		public event AsynThreadEventHandler OperationCompleted = null;
		public event AsynThreadEventHandler OperationFaulted = null;
		public event AsynThreadEventHandler OperationAborted = null;


		// =================================================
		// Properties
		// =================================================

		private AsynThreadFunc _initThread = null;
		public AsynThreadFunc InitThread
		{
			get { return _initThread; }
			set { _initThread = value; }
		}

		private ThreadUserState _userState;
		public ThreadUserState UserState
		{
			get { return _userState; }
			set { _userState = value; }
		}

		private Thread _comThread = null;


		// =================================================
		// Constructors
		// =================================================


		public AsyncThread()
		{
			
		}

		public AsyncThread(AsynThreadFunc func)
		{
			_initThread = func;
		}


		// =================================================
		// Public methods
		// =================================================

		/// <summary>
		/// Start thread
		/// </summary>
		/// <param name="args">Input parameters</param>
		public void Start(params object[] args)
		{
			if (InitThread == null)
				OnOperationError("Cannot start thread: Reference to a null object.");
			else
			{
				try
				{
					ParameterizedThreadStart ts = new ParameterizedThreadStart(ExecuteMethod);
					_comThread = new Thread(ts);
					_comThread.Start(args);

				}

				catch (Exception ex)
				{
					OnOperationError(ex.Message);
				}
			}
		}

		/// <summary>
		/// Stop thread and raise Aborted event
		/// </summary>
		public void Stop()
		{
			if (_comThread != null)
			{
				_comThread.Abort();
				OnOperationAborted();
			}
		}


		// =================================================
		// Private methods
		// =================================================


		private void ExecuteMethod(object args)
		{
			if (InitThread != null)
				InitThread(args);


			// Raise operation complete if no error occur.
			OnCompleted();
		}

		private void OnOperationError(string errorMessage)
		{
			if (OperationFaulted != null)
			{
				ThreadEventArgs tea = new ThreadEventArgs(errorMessage);
				tea.Canceled = true;
				OperationFaulted(this, tea);
			}
		}

		private void OnCompleted()
		{
			if (OperationCompleted != null)
			{
				ThreadEventArgs tea = new ThreadEventArgs("Successful");
				OperationCompleted(this, tea);
			}
		}

		private void OnOperationAborted()
		{
			if (OperationAborted != null)
			{
				ThreadEventArgs tea = new ThreadEventArgs("Operation was aborted by user.");
				tea.Canceled = true;
				OperationAborted(this, tea);
			}
		}
	}
}
